package deng.jboss.jbossmc;

import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.jboss.kernel.plugins.bootstrap.standalone.StandaloneBootstrap;
import org.jboss.kernel.spi.registry.KernelBus;

/**
 * Bootstrap a JBoss Microcontainer and invoke a bean with one or more methods.
 * 
 * <p>These are options you may pass to this program</p>
<pre>
	-DrunBeanId=<name>           One of the jboss deployed bean name.
	-DrunBeanMethods=<csv_names> One or more parameterless, public methods to be invoked in the bean.
	-DkeepAlive=true             Place the main thread to a wait state after invoke all methods. 
</pre>
 *
 * <p>If no runBeanId are given, then it will not invoke any bean. Although the deployment may
 * declare to have any lifecycle methods to be invoke(like create or start etc).</p>
 * 
 * @author Zemian Deng <saltnlight5@gmail.com>
 *
 */
public class JBossMCRunner extends StandaloneBootstrap {
	
	// ========== Main program entry
	public static void main(String[] args) {
		try {
			JBossMCRunner runner = new JBossMCRunner();
			runner.init(args);
			runner.run();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	// ========== Constructors
	public JBossMCRunner() throws Exception {
		super(new String[]{});
	}
	
	public JBossMCRunner(String[] args) throws Exception {
		super(args);
	}
	
	// ========== Fields
	protected boolean keepAlive;
	protected String runBeanId;
	protected List<String> runBeanMethods;
	protected List<URL> configUrls;
	
	// ========== External Methods
	public void run() {
		try {
			// Bootstrap the JBoss Microcontainer and deploy all the configUrls
			bootstrap();
			for (URL configUrl : configUrls) {
				log.debug("Deploying " + configUrl);
				deploy(configUrl);
			}
			
			// Invoke bean
			if (runBeanId != null && runBeanMethods.size() > 0) {
				log.debug("Invoking bean " + runBeanId);
				for (String methodName : runBeanMethods) {
					log.debug("Invoking method " + methodName);
					invoke(runBeanId, methodName);
				}
			}

			
			// Keep alive
			if (keepAlive) {
				log.debug("Running in keepAlive mode. Use CTRL+C to shutdown.");
				synchronized (this) {
					this.wait();
				}
			}
		} catch (Throwable e) {
			throw new RuntimeException("Failed to bootstrap and run JBoss Microcontianer.", e);
		}
	}
	
	public void init(String[] args) {
		// Initialize instance
		keepAlive = Boolean.valueOf(System.getProperty("keepAlive", "false"));
		runBeanId = System.getProperty("runBeanId", null);
		String[] runBeanMethodNames = System.getProperty("runBeanMethods", "run").split("\\s*,\\s*");
		runBeanMethods = Arrays.asList(runBeanMethodNames);
		
		configUrls = new ArrayList<URL>();
		try {
			if (args.length > 0) {
				configUrls.add(new URL("classpath:/META-INF/jboss-beans.xml"));
			} else {
				for (String arg : args) {
					File file = new File(arg);
					if (file.exists()) {
						configUrls.add(file.toURI().toURL());
					} else {
						configUrls.add(new URL(arg));						
					}
				}
			}
		} catch (Exception e) {
			throw new RuntimeException("Failed to create configUrls.", e);
		}
	}
	
	// ========== Internal Methods
	private void invoke(String serviceName, String methodName) {
		Object[] args = new Object[]{}; 
		String[] types = new String[]{};
		KernelBus bus = getKernel().getBus();
	    try {
	        bus.invoke(serviceName, methodName, args, types);
	    } catch (Throwable t) {
	        throw new RuntimeException("Failed to execute " + serviceName + ": " + methodName, t);
	    }
	}

	// ========== Getters and Setters
	public void setConfigUrls(List<URL> configUrls) {
		this.configUrls = configUrls;
	}	
	public void setRunBeanId(String runBeanId) {
		this.runBeanId = runBeanId;
	}	
	public void setRunBeanMethods(List<String> runBeanMethods) {
		this.runBeanMethods = runBeanMethods;
	}
}
